//CliTools.cpp : Defines the exported functions for the DLL application.
#include "CliTools.unmanaged.h"

#define BUFFER_SIZE 1024
#define COUNT_OF_TOKENS 3

#pragma warning( disable : 4267 )
using namespace std;

extern "C" __declspec(dllexport) void usage()
{
    printf("\r\n");
    printf("USAGE: DWARF (Parallel Pattern)\r\n");
    printf("    dwarfname [/?] [/help] [/log:type] [/inputfile:file] [/profilefile:file] [/resultfile:file] [/threadcount:int]\r\n");
    printf("              [{/env:name=val}*]\r\n");
    printf("\r\n");
    printf("where\r\n");
    printf("    options:\r\n");
    printf("        /? /help         - Display help message.\r\n");
    printf("        /inputfile       - Matrix of distances.\r\n");
    printf("        /profilefile     - Specify output file name for runtime data.\r\n");
    printf("        /resultfile      - Specify output file name for computation results.\r\n");
    printf("        /threadcount     - Count of execution parts.\r\n");
    printf("        /gui             - Run with graphical user interface.\r\n");
    printf("        /env             - Set environment variables.\r\n");
}

extern "C" __declspec(dllexport) int parseArguments(   
    int argc,
    char **argv,
    char **inputFile,
    char **profileFile,
	char **resultFile)
{  
    int count, i;
	int *token = new int[COUNT_OF_TOKENS];		
	for (int i = 0; i < COUNT_OF_TOKENS; i++)
	{
		token[i] = 1;						// token[i] indicates that 'i'-token don't consist in argv
	} 

	for (i = 0; i < argc; i ++) {
	    if (argv[i][0] != '/') {
		    continue;
	    } else if (!strcmp(argv[i], "/?") || !strcmp(argv[i], "/help")) {
		    usage();
            return -1;
		} else if (!strncmp(argv[i], "/inputfile", 10)) { 
		    count = strlen(argv[i]) - 11 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*inputFile, argv[i] + 11, count);
			token[0]--;						// right defined inputfile-token was found in argv
	    } else if (!strncmp(argv[i], "/profilefile", 12)) { 
		    count = strlen(argv[i]) - 13 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*profileFile, argv[i] + 13, count);
			if(!strncmp(*inputFile, *profileFile, BUFFER_SIZE))
			{
				printf("File names must differ!\r\n"); 
				return -1;
			}
			token[1]--;						// right defined profilefile-token was found in argv
		} else if (!strncmp(argv[i], "/resultfile", 11)) { 
		    count = strlen(argv[i]) - 12 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*resultFile, argv[i] + 12, count);
			if(!strncmp(*resultFile, *profileFile, BUFFER_SIZE))
			{
				printf("File names must differ!\r\n");
				return -1;
			}
			token[2]--;						// right defined resultfile-token was found in arygv
	    }
    }  

	for (int i = 1; i < COUNT_OF_TOKENS; i++)
	{
		token[0] += token[i];				// sum of all 'token entries'
	}
	if(token[0]) usage();
	return token[0];						// if sum is equal to zero, argv was right defined						
}

// not required parameter *threadCount is used for counting the number of threads in processing
extern "C" __declspec(dllexport) int parseArgumentsThreading(   
    int argc,
    char **argv,
    char **inputFile,
    char **profileFile,
	char **resultFile,
	int *threadCount)
{  
    int count, i;
	int *token = new int[COUNT_OF_TOKENS];		
	for (int i = 0; i < COUNT_OF_TOKENS; i++)
	{
		token[i] = 1;						// token[i] indicates that 'i'-token don't consist in argv
	} 

	for (i = 0; i < argc; i ++) {
	    if (argv[i][0] != '/') {
		    continue;
	    } else if (!strcmp(argv[i], "/?") || !strcmp(argv[i], "/help")) {
		    usage();
            return -1;
		} else if (!strncmp(argv[i], "/inputfile", 10)) { 
		    count = strlen(argv[i]) - 11 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*inputFile, argv[i] + 11, count);
			token[0]--;						// right defined inputfile-token was found in argv
	    } else if (!strncmp(argv[i], "/profilefile", 12)) { 
		    count = strlen(argv[i]) - 13 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*profileFile, argv[i] + 13, count);
			if(!strncmp(*inputFile, *profileFile, BUFFER_SIZE))
			{
				printf("File names must differ!:\r\n"); 
				return -1;
			}
			token[1]--;						// right defined profilefile-token was found in argv
		} else if (!strncmp(argv[i], "/resultfile", 11)) { 
		    count = strlen(argv[i]) - 12 + 1;
			if (count > BUFFER_SIZE) return -1;
			memcpy(*resultFile, argv[i] + 12, count);
			if(!strncmp(*resultFile, *profileFile, BUFFER_SIZE))
			{
				printf("File names must differ!\r\n"); 
				return -1;
			}
			token[2]--;						// right defined resultfile-token was found in arygv
	    } else if (!strncmp(argv[i], "/threadcount", 12)) {
		    count = strlen(argv[i]) - 13;
			if (count > BUFFER_SIZE) return -1;
		    *threadCount = 0;
		    for (int j = 0; j < count; j++)	// convert chars to int
		    {
				*threadCount = *threadCount * 10 + ((int)argv[i][13+j] - (int)'0');			
		    }
	    }
    }  

	for (int i = 1; i < COUNT_OF_TOKENS; i++)
	{
		token[0] += token[i];				// sum of all 'token entries'
	}
	if(token[0]) usage();
	return token[0];						// if sum is equal to zero, argv was right defined						
}


static LARGE_INTEGER tstart, tstop;
static LARGE_INTEGER frequency;

extern "C" __declspec(dllexport) void start()
{
	QueryPerformanceFrequency(&frequency);
	QueryPerformanceCounter(&tstart);
}

extern "C" __declspec(dllexport) void stop(double* time)
{	
	QueryPerformanceCounter(&tstop);
	*time = (double)(tstop.QuadPart - tstart.QuadPart) /(double)frequency.QuadPart;
}

extern "C" __declspec(dllexport) double finish()
{	
	QueryPerformanceCounter(&tstop);
	return (double)(tstop.QuadPart - tstart.QuadPart) /(double)frequency.QuadPart;
}
